package com.tanhua.management.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tanhua.common.mapper.UserMapper;
import com.tanhua.common.pojo.User;
import com.tanhua.common.utils.TimeTool;
import com.tanhua.dubbo.server.api.BackgroundDashboardApi;
import com.tanhua.dubbo.server.pojo.LogRecord;
import com.tanhua.management.vo.ParamVo;
import com.tanhua.management.vo.SummaryInfoVo;
import com.tanhua.management.vo.YearVo;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @Author lenny
 * @create 2021/9/17 15:54
 */

@Service
public class BackgroundDashboardService {

    @Autowired
    private UserMapper userMapper;

    @Reference(version = "1.0.0")
    private BackgroundDashboardApi backgroundDashboardApi;

    private Long oneDay=86400000L;
    private Long oneYear= oneDay * 365;
    private Long oneMonth = oneDay * 30 ;
    private Long oneWeek = oneDay * 7 ;


    /**
     * 查询概要统计信息
     * <p>
     * 这里的时间应该是以天为单位,无需太精确,所以都以当天的 晚上0点 为原点,
     *
     * @return
     */
    public SummaryInfoVo summaryInfoStatistics() throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String today = DateUtil.today()+ " 00:00:00";
        long defaultTime = simpleDateFormat.parse(today).getTime();
        //拿到当前 规定 时间 的毫秒值

        long nowTime = System.currentTimeMillis();
        //System.out.println(time);

        //每天共  86400000L 毫秒

        //  X天前(指定的)的时间
        long monthTime = defaultTime - (30 * 86400000L);
        long weekTime = defaultTime - (7 * 86400000L);
        long dayTime = defaultTime - (86400000L);
        long beforeYesterday = defaultTime - (2 * 86400000L);

        //累计用户,拿到所有用户就可以
        Integer totalUsers = userMapper.selectCount(new QueryWrapper<>());

        System.out.println(
                "测试"
        );

        //过去30天活跃的用户.(过去30天有一天登录,即可记为 活跃用户 )
        //4个活跃,都可以公用,因为都是一个'时间段'....月.周.昨日活跃
        Integer monUsers = backgroundDashboardApi.activeUserNum(defaultTime, monthTime);
        Integer weekUser = backgroundDashboardApi.activeUserNum(defaultTime, weekTime);
        Integer yesterdayUsers = backgroundDashboardApi.activeUserNum(defaultTime, dayTime);
        //前天活跃数
        Integer beforeYesterdayUsers = backgroundDashboardApi.activeUserNum(defaultTime, beforeYesterday);

        //-0 时间不会发生变化,产生不了时间段,所以,'今日活跃'需要另外构造一个方法
        Integer todayUsers = backgroundDashboardApi.todayActiveUserNum(defaultTime, nowTime);

        //今日新增用户
        Integer newUsersToday = newUsersNum(defaultTime, nowTime);

        //昨日新增用户............................................
        Integer newUsersYesterday = newUserNum(defaultTime, dayTime);

        //今日登录次数
        Integer loginNumToday = backgroundDashboardApi.loginCount(defaultTime, nowTime);


        //今日新增 涨跌率(参考昨日的进行计算)
        //拿到今日新增用户数和昨日新增用户数,传参
        Integer todayAmplitude = backgroundDashboardApi.newUserAmplitude(newUsersToday, newUsersYesterday);

        //今日活跃 涨跌率
        Integer activeUsersTodayRate = backgroundDashboardApi.activeUserAmplitude(todayUsers, yesterdayUsers);

        //昨日活跃 涨跌率,拿到前天的数据
        Integer activeUsersYesterdayRate = backgroundDashboardApi.activeUserAmplitude(yesterdayUsers, beforeYesterdayUsers);

        //过去7天平均使用时长 ,单位/秒
        Integer averageTime = backgroundDashboardApi.averageUseTime(defaultTime, weekTime);

        //今日登录次数涨跌率.......loginTimesTodayRate
        //昨日登录次数
        Integer loginNumYesterday = backgroundDashboardApi.loginCountBefore(defaultTime, dayTime);

        Integer loginRateToday = backgroundDashboardApi.activeUserAmplitude(loginNumToday, loginNumYesterday);


        SummaryInfoVo summaryInfoVo = new SummaryInfoVo();
        //填充数据
        summaryInfoVo.setCumulativeUsers(totalUsers);
        summaryInfoVo.setActivePassMonth(monUsers);
        summaryInfoVo.setActivePassWeek(weekUser);
        summaryInfoVo.setNewUsersToday(newUsersToday);
        summaryInfoVo.setNewUsersTodayRate(todayAmplitude);
        //今日登录次数
        summaryInfoVo.setLoginTimesToday(loginNumToday);
        summaryInfoVo.setActiveUsersToday(todayUsers);
        summaryInfoVo.setActiveUsersTodayRate(activeUsersTodayRate);
        summaryInfoVo.setUseTimePassWeek(averageTime);
        summaryInfoVo.setLoginTimesTodayRate(loginRateToday);
        summaryInfoVo.setActiveUsersYesterday(yesterdayUsers);
        summaryInfoVo.setActiveUsersYesterdayRate(activeUsersYesterdayRate);

        return summaryInfoVo;

    }

    /**
     * 昨日新增用户
     *
     * @param defaultTime
     * @param dayTime
     * @return
     */
    private Integer newUserNum(long defaultTime, long dayTime) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //拿到时间段
        queryWrapper.
                gt("created", dayTime).
                lt("created", defaultTime);

        return userMapper.selectCount(queryWrapper);
    }

    /**
     * 今日新增用户
     *
     * @param defaultTime
     * @param nowTime
     * @return
     */
    private Integer newUsersNum(long defaultTime, long nowTime) {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        //拿到时间段
        queryWrapper.
                gt("created", new Date(defaultTime)).
                lt("created", new Date(nowTime));

        return userMapper.selectCount(queryWrapper);
    }

    /**
     * 新增,活跃用户,次日留存率
     * created,logtime,
     *
     * @param startTime
     * @param endTime
     * @param type
     * @return 101新增;102活跃用户;103次日留存率  (1..到..12月数据,组成 统计图 )
     */
    public YearVo usersData(Long startTime, Long endTime, String type) {

        //传过来  整点 值 yyyy-MM-dd 00:00:00,测试得知,(86400000 = 24H)
        long ruleEndTime = endTime + oneDay;
        /* ParamVo
         * 日期
        private String title;
         * 数量
        private Integer amount;
        */
        YearVo yearVo = new YearVo();
        switch (type) {
            case "101":
            {
                //获取一段时间内 每一天 新注册的用户
                 yearVo =  queryNewUserByTimePeriod(startTime, ruleEndTime);
                break;
            }
            case "102":
            {
                //活跃
                yearVo = activeUsersData(startTime, ruleEndTime);
                break;
            }
            case "103":{
                //次日留存率
                //yearVo = morrowRetentionRate(startTime, ruleEndTime);
                yearVo = activeUsersData(startTime, ruleEndTime);
                break;
            }
            default:{
                break;
            }
        }
        return yearVo;

    }

    /**
     * 新增
     * 获取一段时间内 每一天 新注册的用户
     * @param startTime
     * @param ruleEndTime
     * @return
     */
    private YearVo queryNewUserByTimePeriod(Long startTime, long ruleEndTime) {
        List<ParamVo> paramVoThisYear = new ArrayList<>();
        List<ParamVo> paramVoLastYear = new ArrayList<>();
        long time = (ruleEndTime - startTime) / oneDay;
        for (long i = 0; i < time; i++) {
            ParamVo paramVo = new ParamVo();
            paramVo.setTitle(new SimpleDateFormat("MM-dd").format(new Date(startTime+(oneDay*i))));
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            //拿到时间段
            queryWrapper
                    .gt(User::getCreated, new Date(startTime+(oneDay*i)))
                    .lt(User::getCreated, new Date(startTime+(oneDay*(i+1))));
            paramVo.setAmount(userMapper.selectCount(queryWrapper));
            paramVoThisYear.add(paramVo);
//            System.out.println(new Date(startTime+(oneDay*i)));
            ParamVo paramVo1 = new ParamVo();
            paramVo1.setTitle(new SimpleDateFormat("MM-dd").format(new Date(startTime+(oneDay*i)-oneYear)));
            LambdaQueryWrapper<User> queryWrapper1 = new LambdaQueryWrapper<>();
            //拿到时间段
            queryWrapper1
                    .gt(User::getCreated,new Date(startTime+(oneDay*i)-oneYear))
                    .lt(User::getCreated, new Date(startTime+(oneDay*(i+1))-oneYear));
            paramVo1.setAmount(userMapper.selectCount(queryWrapper1));
            paramVoLastYear.add(paramVo1);
        }
        YearVo yearVo =new YearVo();
        yearVo.setThisYear(paramVoThisYear);
        yearVo.setLastYear(paramVoLastYear);
        return yearVo;
    }

    /**
     * 次日留存率
     * @param startTime
     * @param ruleEndTime
     * @return
     */
    private YearVo morrowRetentionRate(Long startTime, Long ruleEndTime) {
        List<ParamVo> paramVoThisYear = new ArrayList<>();
        List<ParamVo> paramVoLastYear = new ArrayList<>();
        List<Object> idList1 =new ArrayList<>();
        List<Object> idList2 =new ArrayList<>();
        List<Object> idList11 =new ArrayList<>();
        List<Object> idList21 =new ArrayList<>();
        //先去userMapper找  第一天 create当天的返回一个 idList1 集合
        long time = (ruleEndTime - startTime) / oneDay;

        for (long i = 0; i < time; i++) {
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            ParamVo paramVo = new ParamVo();
            paramVo.setTitle(new SimpleDateFormat("MM-dd").format(new Date(startTime+(oneDay*i))));
            //拿到时间段
            queryWrapper
                    .gt(User::getCreated, new Date(startTime + (oneDay * i)))
                    .lt(User::getCreated, new Date(startTime + (oneDay * (i + 1))));
            List<User> userList = userMapper.selectList(queryWrapper);
            idList1  =  CollUtil.getFieldValues(userList,"id");
        //再去mongodb中查找 第二天 查找当天访问过的     idList2 集合
            List<LogRecord> userList1 = backgroundDashboardApi.queryNextDayLeft(startTime+(oneDay*i),startTime+(oneDay*(i+1)));
            idList2  =  CollUtil.getFieldValues(userList1,"userId");
        //次日留存率 （ count/idList1）
            int count = receiveCollectionList(idList1, idList2).size();
            if (idList1.size()==0){
                paramVo.setAmount(0);
            }else {
                paramVo.setAmount(count/idList1.size());
            }

            paramVoThisYear.add(paramVo);

            //去年的
            LambdaQueryWrapper<User> queryWrapper1 = new LambdaQueryWrapper<>();
            ParamVo paramVo1 = new ParamVo();
            paramVo1.setTitle(new SimpleDateFormat("MM-dd").format(new Date(startTime+(oneDay*i)-oneYear)));
            queryWrapper1
                    .gt(User::getCreated, new Date(startTime + (oneDay * i)-oneYear))
                    .lt(User::getCreated, new Date(startTime + (oneDay * (i + 1))-oneYear));
            idList11  =  CollUtil.getFieldValues(userMapper.selectList(queryWrapper1),"id");
            //再去mongodb中查找 第二天 查找当天访问过的     idList2 集合
            idList21  =  CollUtil.getFieldValues(backgroundDashboardApi.queryNextDayLeft(startTime+(oneDay*i)-oneYear,startTime+(oneDay*(i+1))-oneYear),"userId");
            //次日留存率 = count/idList1.size()
            int count1  = receiveCollectionList(idList11, idList21).size();
            if(idList11.size()==0){
                paramVo1.setAmount(0);
            }else {
                paramVo1.setAmount(count1/idList11.size());
            }
            paramVoLastYear.add(paramVo);
        }

        YearVo yearVo =new YearVo();
        yearVo.setThisYear(paramVoThisYear);
        yearVo.setLastYear(paramVoLastYear);
        return yearVo;
    }

    /**
     * @方法描述：获取两个ArrayList的交集
     * @param firstArrayList 第一个ArrayList
     * @param secondArrayList 第二个ArrayList
     * @return resultList 交集ArrayList
     */
    public static List<Object> receiveCollectionList(List<Object> firstArrayList, List<Object> secondArrayList) {
        List<Object> resultList = new ArrayList<>();
        LinkedList<Object> result = new LinkedList<>(firstArrayList);// 大集合用linkedlist
        HashSet<Object> othHash = new HashSet<>(secondArrayList);// 小集合用hashset
        Iterator<Object> iter = result.iterator();// 采用Iterator迭代器进行数据的操作
        while (iter.hasNext()) {
            if (!othHash.contains(iter.next())) {
                iter.remove();
            }
        }
        resultList = new ArrayList<Object>(result);
        return resultList;

    }
    /**
     * 活跃用户
     * @param startTime
     * @param ruleEndTime
     * @return
     */
    private YearVo activeUsersData(Long startTime, Long ruleEndTime) {
        List<ParamVo> paramVoThisYear = new ArrayList<>();
        List<ParamVo> paramVoLastYear = new ArrayList<>();
        long time = (ruleEndTime - startTime) / oneDay;
        for (long i = 0; i < time; i++) {
            ParamVo paramVo = new ParamVo();
            paramVo.setTitle(new SimpleDateFormat("MM-dd").format(new Date(startTime+(oneDay*i))));
            //拿到时间段
            paramVo.setAmount(backgroundDashboardApi.queryActiveUserCountByDate(startTime+(oneDay*i),startTime+(oneDay*(i+1))));
            paramVoThisYear.add(paramVo);

           //System.out.println(paramVoThisYear.size()+":"+new SimpleDateFormat("MM-dd").format(new Date(startTime+(oneDay*i)))+":"+paramVo.getAmount());

            ParamVo paramVo1 = new ParamVo();
            paramVo1.setTitle(new SimpleDateFormat("MM-dd").format(new Date(startTime+(oneDay*i)-oneYear)));
            paramVo1.setAmount(backgroundDashboardApi.queryActiveUserCountByDate(startTime+(oneDay*i)-oneYear,startTime+(oneDay*(i+1))-oneYear));
            paramVoLastYear.add(paramVo1);
        }

        YearVo yearVo =new YearVo();
        yearVo.setThisYear(paramVoThisYear);
        yearVo.setLastYear(paramVoLastYear);
        return yearVo;
    }



    /**
     * 活跃用户
     *
     * @param sd
     * @param ed
     * @return
     */
    private YearVo queryActiveUserByDate(Date sd, Date ed) {
        YearVo yearVo = new YearVo();
        //转换为毫秒值
        long startTime = sd.getTime();
        long endTime = ed.getTime();
        //查询今年时间段活跃用户
        int thisYearActiveUser = backgroundDashboardApi.queryActiveUserCountByDate(endTime, startTime);
        //获取今年年份
        int thisYear = DateUtil.year(ed);//获取年份
        //封装数据

        ParamVo thisYearData = new ParamVo();
        thisYearData.setTitle(String.valueOf(thisYear));
        thisYearData.setAmount(thisYearActiveUser);
        List<ParamVo> thisYears = new ArrayList<>();
        thisYears.add(thisYearData);
        yearVo.setThisYear(thisYears);
        //去年
        long lastStartTime = DateUtils.addYears(sd, -1).getTime();
        long lastEndTime = DateUtils.addYears(ed, -1).getTime();
        //查询去年时间段活跃用户
        int lastYearActiveUser = backgroundDashboardApi.queryActiveUserCountByDate(lastEndTime, lastStartTime);
        //获取去年年份
        int lastYear = DateUtil.year(DateUtils.addYears(ed, -1));//获取年份
        //封装数据
        ParamVo lastYearData = new ParamVo();
        lastYearData.setTitle(String.valueOf(lastYear));
        lastYearData.setAmount(lastYearActiveUser);
        List<ParamVo> lastYears = new ArrayList<>();
        lastYears.add(lastYearData);
        yearVo.setLastYear(lastYears);

        return yearVo;
    }
}

